package cn.tedu.user.service;

import cn.tedu.user.mapper.UserMapper;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.jt.common.pojo.User;
import com.jt.common.utils.MD5Util;
import com.jt.common.utils.MapperUtil;
import com.jt.common.utils.UUIDUtil;
import com.jt.common.vo.SysResult;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import redis.clients.jedis.JedisCluster;

@Service
public class UserService {
    @Autowired
    UserMapper um;

    @Autowired
    JedisCluster jedisCluster;

    /**
     * 登录ticket的redis有效时间
     */
    int loginLife = 60 * 60 * 2;

    public SysResult checkUserName(String userName) {
        int exist = um.selectCountByUserName(userName);
        if (exist == 1) {
            //表示已经存在 不可用 status=201
            return SysResult.build(201, "", null);
        } else {
            // 表示可用 status=200
            return SysResult.ok();
        }
    }

    /**
     * 注册用户
     * @param user
     */
    public void saveUser(User user) {
        // user对象作为表单数据的接收，缺少userId
        String userId = UUIDUtil.getUUID();
        user.setUserId(userId);
        // user的password是明文，需要进行加密处理，md5
        // md5加盐
        // 让用户的密码看起来不像密码 12k93MDK2 123456+"aljfladsjf1sad"
        String pasMd5 = MD5Util.md5(user.getUserPassword());
        user.setUserPassword(pasMd5);
        um.insertUser(user);
    }

    public String doLogin(User user) {
        // 1. 判断合法
        // 2. 存储redis

        // 准备一个返回的字符串，默认值""
        String ticket = "";
        // 使用user参数，查询数据库，判断是否存在user行数据，验证合法
        // user里明文password加密
        user.setUserPassword(MD5Util.md5(user.getUserPassword()));
        User exist = um.selectUserByNameAndPw(user);
        if (exist == null) {
            // 说明没有查询到user对象登录时不合法
        } else {
            // 一旦进入else说明登录校验成功，先生成本次登录使用的ticket
            // 给ticket赋值 ticket体现特点：用户不同时，ticket不同，同一个用户不同时间登录，生成的ticket也不同
            ticket = "EM_TICKET" + System.currentTimeMillis() + user.getUserName();
            // 生成顶替逻辑中的userId的唯一值
            String loginKey = "login_" + exist.getUserId();
            // 判断是否需要顶替
            if (jedisCluster.exists(loginKey)) {
                // 进入到if说明有人已经登录，要将它登录时使用的ticket删除
                String lastTicket = jedisCluster.get(loginKey);
                jedisCluster.del(lastTicket);
                // 在这个loginKey覆盖上次登录的有效ticket
                jedisCluster.set(loginKey, ticket);
            } else {
                // 如果不存在，就把自己登录时用的2个key-value设置在redis
                jedisCluster.set(loginKey, ticket);
            }

            // 数据合法
            // 创建key-value的数据将用户信息存储在redis供客户端后续访问使用
            // 准备一个数据 user json字符串，可以将密码做空 redis的value
            // 调用一个对象的api ObjectMapper 可以将json和对象进行相互转化 writeValueAsString readValue
            exist.setUserPassword(null);
            // 将exist转化为json
            ObjectMapper om = MapperUtil.MP;
            try {
                String uJson = om.writeValueAsString(exist);
                // 需要存储在redis的key和value都准备好了，下面可以set方法调用6380
                jedisCluster.setex(ticket, loginLife, uJson);
            } catch (Exception e) {
                e.printStackTrace();
                return ticket;
            }
        }
        return ticket;
    }

    /**
     * 根据ticket查询redis中数据
     * @param ticket
     * @return
     */
    public String queryUserData(String ticket) {
        try {
            // 实现续租逻辑，判断剩余时间。如果有人访问超过了90分钟，剩余30分钟，小于30分钟，给超时判断剩余时间
            Long leftTime = jedisCluster.pttl(ticket);
            if (leftTime < 30 * 60 * 1000) {
                // 剩余时间已经不足30分钟，重新刷一次超时，改为2个小时
                jedisCluster.pexpire(ticket, 1000 * loginLife);
            }
            // get方法返回get数据
            return jedisCluster.get(ticket);
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    public void clearRedis(String ticket) {
        try {
            jedisCluster.del(ticket);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
